<script setup>
import { ref,defineProps, onMounted} from 'vue'
import lizi from '@/assets/images/lizi.png'
import * as echarts from 'echarts';
import 'echarts-gl';

const initLz = ()=>{
  const canvas = document.getElementById("canvas");
  const ctx = canvas.getContext("2d");
  const width = 247;
  const height = 132;
  let imgDate = null
  canvas.width = width;
  canvas.height = height;
  var img = new Image();
  img.src = lizi
  img.onload = function() {
    ctx.drawImage(img, 0, 0, width, height);
    imgDate = ctx.getImageData(0, 0, width, height);
    // console.log(imgDate,'img');
    var imageData =  imgDate.data
    var jg = 5
    //获取所有像素点R颜色不是0的像素点的位置以及坐标
    var zb = []
    for (let i = 1; i <= height; i+=jg) {
      for (let j = 1; j < width; j+=jg) {
        var Rij = [(j-1) + (i-1)*imgDate.width]*4 
        var Gij = [(j-1) + (i-1)*imgDate.width]*4 + 1
        var Bij = [(j-1) + (i-1)*imgDate.width]*4 + 2
        var Aij = [(j-1) + (i-1)*imgDate.width]*4 + 3
        if(imageData[Rij]&&imageData[Rij]!==255){
          zb.push({
            x:j,
            y:i,
            R:imageData[Rij],
            G:imageData[Gij],
            B:imageData[Bij],
            A:imageData[Aij]
          })
        }
      }
    }
    // console.log(zb,'zb');
    //清空画布并且在坐标填充粒子并随机运动，运动范围不超5像素
    // setInterval(()=>{
    //   zb.forEach((item,i)=>{
    //     ctx.fillStyle = `rgba(${item.R},${item.G},${item.B},${item.A})`;
    //     ctx.fillRect(item.x, item.y, 1, 1);
    //     //粒子运动

    //   })
    // },10)
    // ctx.clearRect(0, 0, width, height);
    // console.log(Math.random());
    function _getRandomNumber(min, max) {
      return Math.floor(Math.random() * (max - min + 1)) + min;
    }
    setInterval(()=>{
      ctx.clearRect(0, 0, width, height);

      ctx.drawImage(img, 0, 0, width, height);
      zb.forEach((item,i)=>{
        ctx.fillStyle = `rgba(${item.R},${item.G},${item.B},${item.A/100})`;
        ctx.fillRect(item.x+_getRandomNumber(-2,2), item.y+_getRandomNumber(-1,1), 1, 1);
      })
    },100)
    // console.log(imgDate,'imgDate');
    // imgDate.data.forEach((element,i) => {
    //   if(element!=0){
    //     // console.log(i,element);
    //   }
    // });
  }
}

const optionData= [{
  name: '变一',
  value: 40,
  itemStyle: {
    color: '#93DBFF',
  }
}, {
  name: '变二',
  value: 30,
  itemStyle: {
    color: '#5AF3B8'
  }
}, {
  name: '变三',
  value: 20,
  itemStyle: {
    color: '#FFD982'
  }
}, {
  name: '变四',
  value: 20,
  itemStyle: {
    color: '#4D74FF'
  }
}]
let option = null
let myChart = ref(null);
let chart = ref(null);
const init = ()=> {
  //构建3d饼状图
  // let myChart = echarts.init(document.getElementById('cityGreenLand-charts'));
  myChart = echarts.init(chart.value);
  // 传入数据生成 option
  option = getPie3D(optionData, 0.8);
  // console.log(myChart,'myChart');
  myChart.setOption(option);
  //是否需要label指引线，如果要就添加一个透明的2d饼状图并调整角度使得labelLine和3d的饼状图对齐，并再次setOption
  // option.series.push({
  //   name: 'pie2d',
  //   type: 'pie',
  //   labelLine:{
  //     length:20,
  //     length2:5
  //   },
  //   startAngle: -20 , //起始角度，支持范围[0, 360]。
  //   clockwise: false,//饼图的扇区是否是顺时针排布。上述这两项配置主要是为了对齐3d的样式
  //   radius: ['40%', '50%'],
  //   center: ['50%', '45%'],
  //   data: optionData,
  //   itemStyle:{
  //     opacity:1
  //   }
  // });
  myChart.setOption(option);
  bindListen(myChart);
}

const getPie3D = (pieData, internalDiameterRatio) => {
  //internalDiameterRatio:透明的空心占比
  let that = this;
  let series = [];
  let sumValue = 0;
  let startValue = 0;
  let endValue = 0;
  let legendData = [];
  let legendBfb = [];
  let k = 0.15;
  pieData.sort((a, b) => {
    return (b.value - a.value);
  });
  // 为每一个饼图数据，生成一个 series-surface 配置
  for (let i = 0; i < pieData.length; i++) {
    sumValue += pieData[i].value;
    let seriesItem = {
      name: typeof pieData[i].name === 'undefined' ? `series${i}` : pieData[i].name,
      type: 'surface',
      parametric: true,
      wireframe: {
        show: false
      },
      pieData: pieData[i],
      pieStatus: {
        selected: false,
        hovered: false,
        k: k
      },
      shading : 'color',
      center: ['10%', '50%']
    };

    if (typeof pieData[i].itemStyle != 'undefined') {
      let itemStyle = {opacity:0.7};
      typeof pieData[i].itemStyle.color != 'undefined' ? itemStyle.color = pieData[i].itemStyle.color : null;
      typeof pieData[i].itemStyle.opacity != 'undefined' ? itemStyle.opacity = pieData[i].itemStyle.opacity : null;
      seriesItem.itemStyle = itemStyle;
    }
    series.push(seriesItem);
  }

  // 使用上一次遍历时，计算出的数据和 sumValue，调用 getParametricEquation 函数，
  // 向每个 series-surface 传入不同的参数方程 series-surface.parametricEquation，也就是实现每一个扇形。
  legendData = [];
  legendBfb = [];
  for (let i = 0; i < series.length; i++) {
    endValue = startValue + series[i].pieData.value;
    series[i].pieData.startRatio = startValue / sumValue;
    series[i].pieData.endRatio = endValue / sumValue;
    series[i].parametricEquation = getParametricEquation(series[i].pieData.startRatio, series[i].pieData.endRatio,
      false, false, k, series[i].pieData.value);
    startValue = endValue;
    let bfb = fomatFloat(series[i].pieData.value / sumValue, 4);
    legendData.push({
      name: series[i].name,
      value: bfb
    });
    legendBfb.push({
      name: series[i].name,
      value: bfb
    });
  }
  let boxHeight = getHeight3D(series, 13);//通过传参设定3d饼/环的高度，26代表26px
  // 准备待返回的配置项，把准备好的 legendData、series 传入。
  let option = {
    legend: {
      data: legendData,
      orient: 'horizontal',
      left: 10,
      bottom:0 ,
      itemGap: 2,
      textStyle: {
        color: 'rgba(149,209,255,0.7)',
      },
      show: true,
      icon: "rect",
      selectedMode:false,
      itemWidth :10,
      itemHeight :10,
      itemStyle :{
        // color:'rgba(255,255,255,0)',
        // borderWidth:2,
        // borderColor:'#4D74FF'
      },
      formatter: function(param) {
        let item = legendBfb.filter(item => item.name == param)[0];
        // 数组倒排序

        // console.log(legendBfb,param);
        let bfs = fomatFloat(item.value * 100, 2) + "%";
        return `${item.name} `;
      }
    },

    labelLine: {
      show: true,
      lineStyle: {
        color: '#ffffff'
      }
    },
    label: {
      show: false,
      // position: 'ins',
      rich: {
        b: {
          color: '#ffffff',
          fontSize: 10,
          lineHeight: 20
        },
        c: {
          fontSize: 10,
          color: '#ffffff',
        },
      },
      formatter: '{b|{b} \n}{c|{c}}{b|}',

    },
    tooltip: {
      backgroundColor: 'rgba(0,0,0,0.6)',
      borderColor: 'rgba(255,255,255,0.7)',
      borderWidth:2,
      textStyle:{
        color:'#fff'
      },
      formatter: params => {
        if (params.seriesName !== 'mouseoutSeries' && params.seriesName !== 'pie2d') {
          let bfb = ((option.series[params.seriesIndex].pieData.endRatio - option.series[params.seriesIndex].pieData.startRatio) *
            100).toFixed(2);
          return `${params.seriesName}<br/>` +
            `<span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${params.color};"></span>` +
            `${ bfb }%`;
        }
      }
    },
    
    xAxis3D: {
      min: -1,
      max: 1
    },
    yAxis3D: {
      min: -1,
      max: 1
    },
    zAxis3D: {
      min: -1,
      max: 1
    },
    grid3D: {
      show: false,
      top:-3,
      boxHeight: boxHeight, //圆环的高度
      viewControl: { //3d效果可以放大、旋转等，请自己去查看官方配置
        alpha: 26, //角度
        distance: 210,//调整视角到主体的距离，类似调整zoom
        rotateSensitivity: 0, //设置为0无法旋转
        zoomSensitivity: 0, //设置为0无法缩放
        panSensitivity: 0, //设置为0无法平移
        autoRotate: false //自动旋转
      }
    },
    series: series
  };
  return option;
}
//获取3d丙图的最高扇区的高度
const getHeight3D=(series, height)=> {
  series.sort((a, b) => {
    return (b.pieData.value - a.pieData.value);
  })
  return height * 25 / series[0].pieData.value;
}

// 生成扇形的曲面参数方程，用于 series-surface.parametricEquation
const getParametricEquation = (startRatio, endRatio, isSelected, isHovered, k, h) => {
  // 计算
  let midRatio = (startRatio + endRatio) / 2;
  let startRadian = startRatio * Math.PI * 2;
  let endRadian = endRatio * Math.PI * 2;
  let midRadian = midRatio * Math.PI * 2;
  // 如果只有一个扇形，则不实现选中效果。
  if (startRatio === 0 && endRatio === 1) {
    isSelected = false;
  }
  // 通过扇形内径/外径的值，换算出辅助参数 k（默认值 1/3）
  k = typeof k !== 'undefined' ? k : 1 / 3;
  // 计算选中效果分别在 x 轴、y 轴方向上的位移（未选中，则位移均为 0）
  let offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0;
  let offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0;
  // 计算高亮效果的放大比例（未高亮，则比例为 1）
  let hoverRate = isHovered ? 1.05 : 1;
  // 返回曲面参数方程
  return {
    u: {
      min: -Math.PI,
      max: Math.PI * 3,
      step: Math.PI / 32
    },
    v: {
      min: 0,
      max: Math.PI * 2,
      step: Math.PI / 20
    },
    x: function(u, v) {
      if (u < startRadian) {
        return offsetX + Math.cos(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
      }
      if (u > endRadian) {
        return offsetX + Math.cos(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
      }
      return offsetX + Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate;
    },
    y: function(u, v) {
      if (u < startRadian) {
        return offsetY + Math.sin(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
      }
      if (u > endRadian) {
        return offsetY + Math.sin(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
      }
      return offsetY + Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate;
    },
    z: function(u, v) {
      if (u < -Math.PI * 0.5) {
        return Math.sin(u);
      }
      if (u > Math.PI * 2.5) {
        return Math.sin(u) * h * .1;
      }
      return Math.sin(v) > 0 ? 1 * h * .1 : -1;
    }
  };
}

const fomatFloat = (num, n) => {
  var f = parseFloat(num);
  if (isNaN(f)) {
    return false;
  }
  f = Math.round(num * Math.pow(10, n)) / Math.pow(10, n); // n 幂   
  var s = f.toString();
  var rs = s.indexOf('.');
  //判定如果是整数，增加小数点再补0
  if (rs < 0) {
    rs = s.length;
    s += '.';
  }
  while (s.length <= rs + n) {
    s += '0';
  }
  return s;
}

const bindListen = (myChart)=> {
  // 监听鼠标事件，实现饼图选中效果（单选），近似实现高亮（放大）效果。
  let that = this;
  let selectedIndex = '';
  let hoveredIndex = '';
  // 监听点击事件，实现选中效果（单选）
  myChart.on('click', function(params) {
    // 从 option.series 中读取重新渲染扇形所需的参数，将是否选中取反。
    let isSelected = !option.series[params.seriesIndex].pieStatus.selected;
    let isHovered = option.series[params.seriesIndex].pieStatus.hovered;
    let k = option.series[params.seriesIndex].pieStatus.k;
    let startRatio = option.series[params.seriesIndex].pieData.startRatio;
    let endRatio = option.series[params.seriesIndex].pieData.endRatio;
    // 如果之前选中过其他扇形，将其取消选中（对 option 更新）
    if (selectedIndex !== '' && selectedIndex !== params.seriesIndex) {
      option.series[selectedIndex].parametricEquation = getParametricEquation(option.series[
          selectedIndex].pieData
        .startRatio, option.series[selectedIndex].pieData.endRatio, false, false, k, option.series[
          selectedIndex].pieData
        .value);
      option.series[selectedIndex].pieStatus.selected = false;
    }
    // 对当前点击的扇形，执行选中/取消选中操作（对 option 更新）
    option.series[params.seriesIndex].parametricEquation = getParametricEquation(startRatio, endRatio,
      isSelected,
      isHovered, k, option.series[params.seriesIndex].pieData.value);
    option.series[params.seriesIndex].pieStatus.selected = isSelected;
    // 如果本次是选中操作，记录上次选中的扇形对应的系列号 seriesIndex
    isSelected ? selectedIndex = params.seriesIndex : null;
    // 使用更新后的 option，渲染图表
    myChart.setOption(option);
  });
  // 监听 mouseover，近似实现高亮（放大）效果
  myChart.on('mouseover', function(params) {
    // 准备重新渲染扇形所需的参数
    let isSelected;
    let isHovered;
    let startRatio;
    let endRatio;
    let k;
    // 如果触发 mouseover 的扇形当前已高亮，则不做操作
    if (hoveredIndex === params.seriesIndex) {
      return;
      // 否则进行高亮及必要的取消高亮操作
    } else {
      // 如果当前有高亮的扇形，取消其高亮状态（对 option 更新）
      if (hoveredIndex !== '') {
        // 从 option.series 中读取重新渲染扇形所需的参数，将是否高亮设置为 false。
        isSelected = option.series[hoveredIndex].pieStatus.selected;
        isHovered = false;
        startRatio = option.series[hoveredIndex].pieData.startRatio;
        endRatio = option.series[hoveredIndex].pieData.endRatio;
        k = option.series[hoveredIndex].pieStatus.k;
        // 对当前点击的扇形，执行取消高亮操作（对 option 更新）
        option.series[hoveredIndex].parametricEquation = getParametricEquation(startRatio, endRatio,
          isSelected,
          isHovered, k, option.series[hoveredIndex].pieData.value);
        option.series[hoveredIndex].pieStatus.hovered = isHovered;
        // 将此前记录的上次选中的扇形对应的系列号 seriesIndex 清空
        hoveredIndex = '';
      }
      // 如果触发 mouseover 的扇形不是透明圆环，将其高亮（对 option 更新）
      if (params.seriesName !== 'mouseoutSeries' && params.seriesName !== 'pie2d') {
        // 从 option.series 中读取重新渲染扇形所需的参数，将是否高亮设置为 true。
        isSelected = option.series[params.seriesIndex].pieStatus.selected;
        isHovered = true;
        startRatio = option.series[params.seriesIndex].pieData.startRatio;
        endRatio = option.series[params.seriesIndex].pieData.endRatio;
        k = option.series[params.seriesIndex].pieStatus.k;
        // 对当前点击的扇形，执行高亮操作（对 option 更新）
        option.series[params.seriesIndex].parametricEquation = getParametricEquation(startRatio, endRatio,
          isSelected, isHovered, k, option.series[params.seriesIndex].pieData.value + 5);
        option.series[params.seriesIndex].pieStatus.hovered = isHovered;
        // 记录上次高亮的扇形对应的系列号 seriesIndex
        hoveredIndex = params.seriesIndex;
      }
      // 使用更新后的 option，渲染图表
      myChart.setOption(option);
    }
  });
  // 修正取消高亮失败的 bug
  myChart.on('globalout', function() {
    // 准备重新渲染扇形所需的参数
    let isSelected;
    let isHovered;
    let startRatio;
    let endRatio;
    let k;
    if (hoveredIndex !== '') {
      // 从 option.series 中读取重新渲染扇形所需的参数，将是否高亮设置为 true。
      isSelected = option.series[hoveredIndex].pieStatus.selected;
      isHovered = false;
      k = option.series[hoveredIndex].pieStatus.k;
      startRatio = option.series[hoveredIndex].pieData.startRatio;
      endRatio = option.series[hoveredIndex].pieData.endRatio;
      // 对当前点击的扇形，执行取消高亮操作（对 option 更新）
      option.series[hoveredIndex].parametricEquation = getParametricEquation(startRatio, endRatio,
        isSelected,
        isHovered, k, option.series[hoveredIndex].pieData.value);
      option.series[hoveredIndex].pieStatus.hovered = isHovered;
      // 将此前记录的上次选中的扇形对应的系列号 seriesIndex 清空
      hoveredIndex = '';
    }
    // 使用更新后的 option，渲染图表
    myChart.setOption(option);
  });
}
onMounted(() => {
  // console.log('Box mounted')
  initLz()
  init()
})
</script>

<template>
    
    <div class="chart1">
      <div class="lizi">
        <canvas id="canvas" width="247" height="132"></canvas>
      </div>
      <div class="bt">
        <div class="chartBox" ref="chart"></div>
      </div>
      <div class="percent">27.27%</div>
      <div class="classify">变二</div>
      <div class="xian"></div>

      <!-- <ul class="classifyList">
        <li class="classifyItem">
          <div class="classifyLabel" style="background: rgba(73,195,132,0.2);border: 1px solid rgba(73,195,132,1);"></div>
          <div class="classifyName">变一</div>
        </li>
        <li class="classifyItem">
          <div class="classifyLabel" style="background: rgba(156,190,207,0.2);border: 1px solid rgba(156,190,207,1);"></div>
          <div class="classifyName">变二</div>
        </li>
        <li class="classifyItem">
          <div class="classifyLabel" style="background: rgba(44,143,244,0.2);border:1px solid #2b8ef3"></div>
          <div class="classifyName">变三</div>
        </li>
        <li class="classifyItem">
          <div class="classifyLabel" style="background: rgba(221,210,70,0.2);border: 1px solid rgba(221,210,70,1);"></div>
          <div class="classifyName">变四</div>
        </li>
      </ul> -->
    </div>
</template>

<style scoped>
/* .chart1>img{
  display: block;
  width: 100%;
  margin-bottom: 10px;
} */
.percent{
  font-size: 12px;
  line-height: 14px;
  color:#fff;
  position: absolute;
  top: 64px;
  left: 30px;
}
.classify{
  font-size: 8px;
  line-height: 12px;
  color: #95D1FF;
  position: absolute;
  top: 80px;
  left: 48px;
}
.classifyList{
  width: 100%;
  list-style: none;
  overflow: hidden;
  margin: 0;
  padding: 0;
  display: flex;
  justify-content: center;
}
.classifyItem{
  margin-right: 12px;
  display: flex;
  align-items: center;
  height: 14px;
  line-height: 14px;
}
.classifyItem:last-child{
  margin-right: 0;
}
.classifyLabel{
  width: 6px;
  height: 6px;
  box-sizing: border-box;
  margin-right: 4px;
  margin-top: 2px;
}
.classifyName{
  font-size: 10px;
  opacity: 0.7;
  color: #95D1FF;
}
.lizi {
  position: absolute;
  top: 88px;
  z-index: 10;
}
.bt {
  width:100%;
  height: 185px;
  position: relative;
  z-index: 11;
  top:-40px;
}
.chartBox{
  height: 100%;
		width: 100%;
}
.xian {
  background: url(../assets/images/xian.png) no-repeat;
  background-size:100% ;
  width: 54px;
  height: 19.5px;
  position: absolute;
  top: 92px;
    left: 40px;
}
</style>
